<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ES6</title>

  </head>
  <body>

  <script>
    // Symbol 的值是唯一的，用来解决命名冲突的问题 不能用于其他数据进行运算 定义的对象属性不能用for...in循环遍历，但是可以使用Reflect.ownKeys来获取所有对象的所有键名

    // 保证不会与其他属性名产生重名的冲突
    // Symbol 是一个原始类型的值不是对象 不能new，所以不能添加属性
    // Symbol函数可以接受一个字符串作为参数，有利于区分。
      let s = Symbol();
      console.log(s,typeof s);
    // 如果Symbol接受的参数是一个对象，那么就会调用这个对象的toString方法，将其转换为字符串，然后生成一个Symbol值
      const obj = {
          toString(){
            return 'abc123'
          }
        }
      console.log(Symbol(obj))
      // Symbol函数的参数只是表示对当前的Symbol值的描述,相同参数的Symbol函数的返回值是不相等的
      let s1 = Symbol();
      let s2 = Symbol();
      console.log(s1===s2);
      let S3 = Symbol('foo');
      let S4 = Symbol('foo');
      console.log(S3===S4);
      let S5 = Symbol.for('foo');
      let S6 = Symbol.for('foo');
      console.log(S5===S6);

    // Symbol的值不可以和其他类型的值进行运算,会报错
      let sym = Symbol('My Symbol');
      // console.log('yyy' + sym);
      // console.log(`your Symbol is ${sym}`);
      // ES2019提供了一个实例属性description,直接返回Symbol的描述
      console.log(sym.description)
      // 但是Symbol值可以显式转化为字符串
      console.log(String(sym));
      console.log(sym.toString());
      // 可以转化为布尔值,但不能转为数值
      console.log(Boolean(sym,!sym));
      // console.log(Number(sym),sym+3);

      // 向对象中添加方法
      let game = {
        up:function () {

        },
        down:function() {

        }
      };
      let fangfa ={
        up:Symbol(),
        down:Symbol()
      };
      game[fangfa.up]= function () {
        console.log('我可以改变形状');
      };
      game[fangfa.down]=()=>{
        console.log('我是methods中的down函数')
      };
      console.log(game);
      game[fangfa.up]();

      // 直接把Symbol方法写入对象
      let test1 = {
        name:'添加Symbol方法',
        [Symbol('say')]:function () {
          console.log('随便说句话呗');
        },
        [Symbol('play')]:function () {
          console.log('随便玩一下吧');
        }
      };
      console.log(test1);
      // 检测是否为某个类的实例
      class Person{
        static [Symbol.hasInstance](param){
          console.log(param);
          console.log('用于检测类型');
          return true;
        }
      }
      let o = {age:66};
      console.log(o instanceof Person);

      // 设置是否连接之后可以展开
      const arr1 = [1,2,3];
      const arr2 = [4,5,6];
      arr1[Symbol.isConcatSpreadable]=true;
      arr2[Symbol.isConcatSpreadable]=false;
      console.log(arr1.concat(arr2));

      // 迭代器
      // 为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署了Iterator接口，就可以完成遍历操作。
      // ES6创建了遍历的for...of循环，Iterator接口主要供for...of消费
      // for...of保存键值，for...in保存索引
      const arr3 = ['香蕉','菠萝','苹果','橙子'];
      for (let i  /*in*/ of arr3){
        console.log(i)
      };
      let iterator = arr3[Symbol.iterator]();
      // next指针一直从头移动到尾部，每调用一次next方法就返回一个包含value和done属性的对象
      iterator.next()
      console.log(iterator.next());//done是否完成到最后一个的状态


      let duixiang = {
        name:'car',
        catergories:[
                'bus',
                'taxi',
                'bike',
                'train',
                'plane'
        ],
        //手动实现Symbol.iterator
        [Symbol.iterator](){
          let index = 0;

          return{
            next:()=>{
              if (index<this.catergories.length){
                const result = {value:this.catergories[index],done:false};
                index++;
                return result;
              }else{
                return {value: undefined,done: true};
              }
            }
          }
        }
      };

      for(let j of duixiang){
        console.log(j);
      }
      // 生成器实际上是特殊的函数 调用next()方法才可以执行。
      // 异步编程 纯回调函数 node fs ajax mongodb
      function * gen(arg) {
        // 函数代码的分割符
        console.log(arg);
        console.log(111);
        let one = yield '第一行';
        console.log(one);
        console.log(222);
        let two = yield '第二行';
        console.log(two);
        console.log(333);
        let three = yield '第三行';
        console.log(three);
        console.log('fourfourfour');
      }
      // 生成器函数可以传参
      let generator = gen('AAA');
      // 生成器next()可以传递实参
      console.log(generator.next());
      console.log(generator.next('实参1号'));
      console.log(generator.next(`实参2号`));
      console.log(generator.next(`实参3号`));
    //     generator.next();
    //     generator.next();
    //     generator.next();
    //     generator.next();
    //   每次返回的是yield后面的语句
      for (let k of gen()){
        console.log(k)
      }

      // setTimeout(()=>{
      //   console.log(111);
      //     setTimeout(()=>{
      //      console.log(222);
      //       setTimeout(()=>{
      //         console.log(333);
      //       },3000);
      //   },2000);
      // },1000);

    function getUsers() {
      setTimeout(()=>{
            console.log('一一一');
            let data = '用户数据';
            generator3.next(data);
          }
      ,1000)
    };

    function getBuys() {
      setTimeout(()=>{
            console.log('二二二');
            let data = '购买数据';
            generator3.next(data);
          }
          ,2000)
    };
    function getGoods() {
      setTimeout(()=>{
            console.log(`三三三`);
            let data = '货物数据';
            generator3.next(data);
          }
          ,3000)
    };

    function * gen2() {
      let users = yield getUsers();
      console.log(users);
      let buys = yield getBuys();
      console.log(buys);
      let goods = yield getGoods();
      console.log(goods);
    }
    let generator3 = gen2();
    generator3.next();

  </script>
  </body>
</html>
